import { app, BrowserWindow, shell, ipcMain, globalShortcut } from "electron";
import { release } from "os";
import { join } from "path";
import logger from "../utils/log";
const exec = require('child_process').exec;
const puppeteer = require('puppeteer');
const axios = require('axios');
const Jimp = require('jimp');
const { joinImages } = require('join-images');

// Disable GPU Acceleration for Windows 7
//if (release().startsWith("6.1")) app.disableHardwareAcceleration();
app.disableHardwareAcceleration();

// Set application name for Windows 10+ notifications
if (process.platform === "win32") app.setAppUserModelId(app.getName());

if (!app.requestSingleInstanceLock()) {
  app.quit();
  process.exit(0);
}

// Remove electron security warnings
// This warning only shows in development mode
// Read more on https://www.electronjs.org/docs/latest/tutorial/security
// process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'

export const ROOT_PATH = {
  // /dist
  dist: join(__dirname, "../.."),
  // /dist or /public
  public: join(__dirname, app.isPackaged ? "../.." : "../../../public"),
};

let win: BrowserWindow | null = null;
// Here, you can also use other preload
const preload = join(__dirname, "../preload/index.js");
// 🚧 Use ['ENV_NAME'] avoid vite:define plugin
const url = `http://${process.env["VITE_DEV_SERVER_HOST"]}:${process.env["VITE_DEV_SERVER_PORT"]}`;
const indexHtml = join(ROOT_PATH.dist, "index.html");

async function createWindow() {
  win = new BrowserWindow({
    width: 900,
    minWidth: 900,
    minHeight: 650,
    height: 650,

    title: "Main window",
    icon: join(ROOT_PATH.public, "favicon.ico"),
    // useContentSize: true,
    frame: false,
    // maximizable: false,
    // minimizable: false,
    // fullscreenable: false,
    transparent: true,
    hasShadow: false,
    // resizable: false,
    webPreferences: {
      preload,
      webSecurity: false,
      // Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
      // Consider using contextBridge.exposeInMainWorld
      // Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
      nodeIntegration: true,
      enableRemoteModule: true,
      contextIsolation: false,
    },
  });
  require('@electron/remote/main').initialize()
  require("@electron/remote/main").enable(win.webContents)
  app.commandLine.appendSwitch("disable-features", "OutOfBlinkCors");
  if (app.isPackaged) {
    win.loadFile(indexHtml);
  } else {
    win.loadURL(url);
    win.webContents.openDevTools();
  }

  // Test actively push message to the Electron-Renderer
  win.webContents.on("did-finish-load", () => {
    win?.webContents.send("main-process-message", new Date().toLocaleString());
  });

  // Make all links open with the browser, not with the application
  win.webContents.setWindowOpenHandler(({ url }) => {
    if (url.startsWith("https:")) shell.openExternal(url);
    return { action: "deny" };
  });
}

let screenshots;
const Screenshots = require('screenshotschange');
const cp = require('child_process');
let sendMsg = null;

app.whenReady().then(() => {
  createWindow()
  screenshots = new Screenshots.default()
  globalShortcut.register('esc', () => {
    if (screenshots.$win?.isFocused()) {
      screenshots.endCapture()
    }
  })
  globalShortcut.register('ctrl + alt + p', () => {
    win?.webContents.send("startShot");
  })
  // 点击确定按钮回调事件
  screenshots.on('ok', (e, buffer, bounds) => {
    let dataBuf = buffer;
    let time, year, month, date, hours, minutes, seconds, filePath;
    time = new Date();
    year = time.getFullYear();
    month = time.getMonth() + 1;
    date = time.getDate();
    hours = time.getHours();
    minutes = time.getMinutes();
    seconds = time.getSeconds();
    sendMsg.sender.send('startCapture-reply', { buff: dataBuf, fileName: `${"".concat(year).concat(month).concat(date).concat(hours).concat(minutes).concat(seconds, ".png")}` })
  })
  // 点击取消按钮回调事件
  screenshots.on('cancel', () => {
    console.log('capture', 'cancel1')
  })
  // 点击保存按钮回调事件
  screenshots.on('save', (e, buffer, bounds) => {
    console.log('capture', buffer, bounds)
  })
});

/* 监听开始截图事件 */
ipcMain.on('startCapture', function (event) {
  sendMsg = event
  screenshots.startCapture()
});

/* 监听浏览器截图事件 */
ipcMain.on('startCaptureChromeImg', async function (event, data) {
  try {
    let isOpenBycdp = await axios.get('http://localhost:9222/json/version')
    if (!!isOpenBycdp) {
      await cdp(isOpenBycdp, event, data)
    } else {
      await closeBrowser()
      setTimeout(async () => {
        await openbrower(event)
      }, 500);
    }
  } catch {
    await closeBrowser()
    setTimeout(async () => {
      await openbrower(event)
    }, 500);
  }
});

// 打开新浏览器
async function openDefaultBrowser(url) {
  const openB = new Promise((resolve, reject) => {
    switch (process.platform) {
      case "darwin":
        exec(`open ${url}`, (error, stdout, stderr) => {
          if (error) {
            reject(error)
          }
        }).on(`exit`, (code) => {
          console.log(`darwin子进程已退出, 退出码 ` + code);
          resolve()
        })
        break;
      case "win32":
        exec(`start ${url}`, (error, stdout, stderr) => {
          if (error) {
            reject(error)
          }
        }).on('exit', (code) => {
          console.log('win32子进程已退出, 退出码 ' + code);
          resolve()
        });
        break;
      default:
        exec(`xdg-open ${url}`, (error, stdout, stderr) => {
          if (error) {
            reject(error)
          }
        }).on('exit', (code) => {
          console.log('xdg-open子进程已退出, 退出码 ' + code);
          resolve()
        });
    }
  });
  return openB
}
async function getBrowerPath() {
  const pa = new Promise((resolve, reject) => {
    exec(`reg query HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App" "Paths\\chrome.exe /v Path`, (error, stdout, stderr) => {
      if (error) {
        reject({
          data: '未在注册表中找到chrome路径！'
        })
      } else {
        let data = stdout.toString().split('REG_SZ')[1].trim() + '\\chrome.exe'
        let lastData = data.split(' ');
        if (lastData.length == 2) {
          resolve(lastData[0] + '" "' + lastData[1])
        } else if (lastData.length == 3) {
          resolve(lastData[0] + '" "' + lastData[1] + '" "' + lastData[2])
        } else {
          resolve(data)
        }
      }
    })
  });
  return pa
}

const kill = require('tree-kill');

/* 新增初始化时关闭所有浏览器进程 */
async function closeBrowser() {
  const close = new Promise((resolve, reject) => {
    let cmd = process.platform === 'win32' ? 'tasklist' : 'ps aux'
    exec(cmd, (err, stdout, stderr) => {
      if (err) {
        reject(err)
      }
      let arr = []
      stdout.split('\n').map(item => {
        arr.push({ name: item.trim().split(/\s+/)[0], pid: item.trim().split(/\s+/)[1] })
      })

      let data = ['chrome.exe']

      let killArr = []
      for (let i = 0; i < arr.length; i++) {
        for (let j = 0; j < data.length; j++) {
          if (arr[i].name == data[j]) {
            killArr.push(arr[i].pid)
          }
        }
      }

      for (let i = 0; i < killArr.length; i++) {
        kill(killArr[i])
      }
      resolve()
    })
  });
  return close
}
let wsKey: any = ''
async function openbrower(event) {
  const open = new Promise(async (resolve, reject) => {
    let browerPath = await getBrowerPath()
    /* 带参数打开浏览器 */
    await openDefaultBrowser(`${browerPath} --remote-debugging-port=9222`);
    /* 获取浏览器信息，与打开的浏览器建立连接 */
    wsKey = await axios.get('http://localhost:9222/json/version');
    resolve(wsKey)
    // setTimeout(async () => {
    // }, 500);
  });
  return open
}

/* 连接浏览器 */
async function cdp(wsKey, event, data) {
  const cdpres = new Promise(async (resolve, reject) => {
    const browser = await puppeteer.connect({
      browserWSEndpoint: wsKey.data.webSocketDebuggerUrl,
      defaultViewport: null,
      args: ['--start-maximized'] //, '--window-size=1920,1080'
    });

    let allPage = await browser.pages()
    let page = null;

    for (let i = 0; i < allPage.length; i++) {
      let isActive = await allPage[i].evaluate(() => {
        return !document.hidden
      })
      if (isActive) {
        page = allPage[i]
      }
    }
    let fileName = `${new Date().getTime()}.png`
    let shotPathAll = `${data}\\${fileName}`
    await autoScroll(page)
    await pageScreenshot(page, `${shotPathAll}`, event).catch(err => console.log(err))
    console.log(shotPathAll)
    resolve(shotPathAll)
  });
  return cdpres
}

// 创建自动滚动函数
async function autoScroll(page) {
  await page.evaluate(async () => {
    await new Promise((resolve, reject) => {
      try {
        const maxScroll = Number.MAX_SAFE_INTEGER
        let lastScroll = 0
        const interval = setInterval(() => {
          window.scrollBy(0, 100)
          const scrollTop = document.documentElement.scrollTop || window.scrollY
          if (scrollTop >= maxScroll || scrollTop === lastScroll) { // 判断触底，或超出js最大安全长度
            window.scrollTo(0, 0)
            clearInterval(interval)
            resolve()
          } else {
            lastScroll = scrollTop
          }
        }, 100) // 100毫秒执行间隔
      } catch (err) {
        console.log(err)
        reject(err)
      }
    })
  })
}

async function pageScreenshot(page, filename, ev) {
  let {
    pageHeight,
    viewport
  } = await page.evaluate(() => {
    return {
      pageHeight: document.body.scrollHeight,
      viewport: {
        height: document.body.clientHeight,
        width: document.body.clientWidth
      }
    };
  });
  let viewHeight = viewport.height  //总高
  let viewWidth = viewport.width    //宽
  let maxViewHeight = viewHeight    //总高
  let partViewCount = Math.ceil(pageHeight / 5000);
  let images = []

  if (partViewCount === 1) {
    let image = await page.screenshot({
      fullPage: true,
      type: 'png'
    })
    images.push(image)
  } else {
    for (let i = 0; i < partViewCount; i++) {
      let image = await page.screenshot({
        fullPage: false,
        type: 'png',
        clip: {
          x: 0,
          y: i * 5000,
          width: viewWidth,
          height: i === partViewCount - 1 ? maxViewHeight % 5000 : 5000,
          scale: 1,
        }
      })
      images.push(image)
    }
  }

  return new Promise(async (resolve, reject) => {
    if (partViewCount == 1) {
      let img = await Jimp.read(images[0])
      img.write(filename)
      ev.sender.send('largeShotsRes', filename)
      resolve()
    } else {
      /* 合并图片 */
      joinImages(images, { direction: 'vertical' }).then((img) => {
        img.toFile(filename).then((data) => {
          // 合并完成
          ev.sender.send('largeShotsRes', filename)
          resolve()
        });
      });
    }
  })
}

app.on("window-all-closed", () => {
  win = null;
  if (process.platform !== "darwin") app.quit();
});

app.on("second-instance", () => {
  if (win) {
    // Focus on the main window if the user tried to open another
    if (win.isMinimized()) win.restore();
    win.focus();
  }
});

app.on("activate", () => {
  const allWindows = BrowserWindow.getAllWindows();
  if (allWindows.length) {
    allWindows[0].focus();
  } else {
    createWindow();
  }
});

ipcMain.on("min", (e) => win.minimize());
ipcMain.on("window-maximize", function () {
  if (win.isFullScreen()) {
    win.setFullScreen(false);
  } else if (win.isMaximized()) {
    win.unmaximize();
  } else {
    win.maximize();
  }
});
ipcMain.on("close", (e) => win.close());
ipcMain.on("reload", (e) => win.reload());

// new window example arg: new windows url
ipcMain.handle("open-win", (event, arg) => {
  const childWindow = new BrowserWindow({
    webPreferences: {
      preload,
    },
  });

  if (app.isPackaged) {
    childWindow.loadFile(indexHtml, { hash: arg });
  } else {
    childWindow.loadURL(`${url}/#${arg}`);
    childWindow.webContents.openDevTools({ mode: "undocked", activate: true });
  }
});
const ElectronStore = require("electron-store");
ElectronStore.initRenderer();

ipcMain.on("log.info", async (event, arg) => {
  logger.info(arg);
});
ipcMain.on("log.error", async (event, arg) => {
  logger.error(arg);
});

ipcMain.on("openLogs", async (event, arg) => {
  shell.openPath(logger.logger.transports.file.getFile().path);
});

ipcMain.on("openFileFolder", async (event, arg) => {
  shell.openPath(arg);
});

ipcMain.on("openLogFolder", async (event, arg) => {
  shell.openPath(logger.logFolder);
});
ipcMain.on("showItemInFolder", async (event, arg) => {
  shell.showItemInFolder(arg);
});
// 在主进程中.
/* 录屏 */
const { desktopCapturer } = require('electron')
ipcMain.on("getScreenId", async (event, arg) => {
  let sources = await desktopCapturer.getSources({ types: ['screen'] })
  event.sender.send('getScreenIdRes', sources[0].id)
})